//
//  CJPControlView.swift
//  CJPack
//
//  Created by 陈警卫 on 2023-06-09.
//

import UIKit
import Foundation
import MediaPlayer

class CJPControlView: UIView {

    /// 全屏回调
    var didFullAction: (() -> ())?
    /// 播放回调
    var didPlayAction: ((Bool) -> ())?
    
    var orientation: CJPlayerOrientation = .port {
        didSet {
            setupFrame()
        }
    }
    
    var player: CJPlayer?
    
    var time: String? {
        didSet {
            if let time = time {
                self.timeL.text = time
                setupFrameUpdate()
            }
        }
    }
    
    var progress: Double? {
        didSet {
            if let progress = progress, !self.isDragging {
                self.slider.value = Float(progress)
            }
        }
    }
    
    var isPlay: Bool = false {
        didSet {
            setupPlaying()
        }
    }
    
    var sumTime: Double = 0
    
    
    var topView: UIView!
    var bottomView: UIView!
    var fullB: UIButton!
    var playB: UIButton!
    var timeL: UILabel!
    var slider: UISlider!
    
    var isDragging: Bool = false // 是否正在拖动
    
    var toolTimer: Timer? // 显示隐藏计时
    var isShowTool: Bool = true
    
    var nimble: CJPNimble!
    
    lazy var volumeSlider: UISlider? = {
        let slider = MPVolumeView()
        for v in slider.subviews {
            if (v.classForCoder.description() == "MPVolumeSlider") {
                return v as? UISlider
            }
        }
        return nil
    }()
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupView()
        setupData()
        setupToolTimer()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        kCJLog("\(self)--deinit")
    }
    
    func setupData() {
        nimble = CJPNimble()
        nimble.setupGesture(self)
        
        nimble.didSingleTap = { [weak self] nimble in
            self?.singleTapAction()
        }
        nimble.didDoubleTap = { [weak self] nimble in
            self?.doubleTapAction()
        }
        
        nimble.didPanBegan = { [weak self] nimble in
            self?.panBegan()
        }
        
        nimble.didPanChanged = { [weak self] nimble, velocity in
            self?.panChanged(velocity: velocity)
        }
        
        nimble.didPanEnded = { [weak self] nimble in
            self?.panEnded()
        }
    }
    
    func setupView() {
        
        self.clipsToBounds = true
        
        self.topView = UIView()
        self.topView.layer.contents = UIImage(named: "CJPlayer_top_shadow")?.cgImage
        self.addSubview(self.topView)
        
        self.bottomView = UIView()
        self.bottomView.layer.contents = UIImage(named: "CJPlayer_bottom_shadow")?.cgImage
        self.addSubview(self.bottomView)
        
        self.fullB = UIButton(type: .custom)
        self.fullB.setImage(UIImage(named: "CJPlayer_fullscreen"), for: .normal)
        self.bottomView.addSubview(self.fullB)
        self.fullB.addTarget(self, action: #selector(actionFull), for: .touchUpInside)
        
        self.timeL = UILabel()
        self.timeL.font = UIFont.systemFont(ofSize: 11, weight: .regular)
        self.timeL.textColor = .white
        self.timeL.text = "00:00/00:00"
        self.bottomView.addSubview(self.timeL)
        
        self.playB = UIButton(type: .custom)
        self.playB.setImage(UIImage(named: "CJPlayer_play"), for: .normal)
        self.bottomView.addSubview(self.playB)
        self.playB.addTarget(self, action: #selector(actionPlay), for: .touchUpInside)
        
        self.slider = UISlider()
        self.slider.minimumValue = 0
        self.slider.maximumValue = 1
        self.slider.minimumTrackTintColor = .white
        self.slider.maximumTrackTintColor = .white.withAlphaComponent(0.4)
        self.slider.setThumbImage(UIImage(named: "CJPlayer_slider"), for: .normal)
        self.bottomView.addSubview(self.slider)
        self.slider.addTarget(self, action: #selector(sliderValueChanged(_:)), for: .valueChanged)
        self.slider.addTarget(self, action: #selector(sliderTouchUpInside(_:)), for: .touchUpInside)
        self.slider.addTarget(self, action: #selector(sliderTouchDown(_:)), for: .touchDown)
        
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        setupFrame()
    }
    
    func setupFrame() {
        
        if orientation == .port {
            
            self.topView.frame = CGRect(x: 0.0, y: 0.0, width: self.cj_width, height: 40.0)
            
            self.bottomView.frame = CGRect(x: 0.0, y: 0.0, width: self.cj_width, height: 40.0)
            self.bottomView.cj_bottom_y = self.cj_bottom
            
            self.fullB.frame = CGRect(x: 0.0, y: 5.0, width: 30.0, height: 30.0)
            self.fullB.cj_right_x = self.bottomView.cj_width - 10.0
            self.fullB.setImage(UIImage(named: "CJPlayer_fullscreen"), for: .normal)
            
            self.playB.frame = CGRect(x: 10.0, y: 5.0, width: 30.0, height: 30.0)
            
        } else if orientation == .portfull || orientation == .landfull {
            
            self.topView.frame = CGRect(x: 0.0, y: 0.0, width: self.cj_width, height: 40.0 + CJScreen.navBarHeight)
            
            self.bottomView.frame = CGRect(x: 0.0, y: 0.0, width: self.cj_width, height: 40.0 + CJScreen.bottomBarHeight)
            self.bottomView.cj_bottom_y = self.cj_bottom
            
            self.fullB.frame = CGRect(x: 0.0, y: 10.0, width: 30.0, height: 30.0)
            self.fullB.cj_right_x = self.bottomView.cj_width - 10.0
            self.fullB.setImage(UIImage(named: "CJPlayer_shrinkscreen"), for: .normal)
            
            self.playB.frame = CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0)
            
            if orientation == .landfull {
                self.playB.cj_x = 20.0
                self.fullB.cj_right_x = self.bottomView.cj_width - 20.0
            }
        }
        
        setupFrameUpdate()
    }
}

extension CJPControlView {
    
    func setupFrameUpdate() {
        
        self.timeL.sizeToFit()
        self.timeL.frame = CGRect(x: 0.0, y: 0.0, width: self.timeL.cj_width, height: self.timeL.cj_height)
        self.timeL.cj_right_x = self.fullB.cj_x - 10.0
        self.timeL.cj_centerY = self.fullB.cj_centerY
        
        self.slider.frame = CGRect(x: self.playB.cj_right_x + 5, y: 0, width: 0, height: 20)
        self.slider.cj_centerY = self.timeL.cj_centerY
        self.slider.cj_right = self.timeL.cj_x - 5
    }
    
    func setupPlaying() {
        if self.isPlay {
            self.playB.setImage(UIImage(named: "CJPlayer_pause"), for: .normal)
        } else {
            self.playB.setImage(UIImage(named: "CJPlayer_play"), for: .normal)
        }
    }
    
}

extension CJPControlView {
    
    /// 全屏实现
    @objc func actionFull() {
        if let didFullAction = didFullAction {
            didFullAction()
        }
        showToolAction()
    }
    
    /// 播放实现
    @objc func actionPlay() {
        guard let player = self.player else { return }
        if player.isPlay {
            player.pause()
        } else {
            player.play()
        }
        showToolAction()
    }
    
    @objc func sliderValueChanged(_ sender: UISlider) {
        guard let currentTime = self.player?.player?.currentItem?.currentTime().seconds,
              let totalTime = self.player?.player?.currentItem?.duration.seconds,
              !currentTime.isNaN && !totalTime.isNaN
        else {
            return
        }
        let loadTime = totalTime * Double(sender.value)
        let timeString = self.player?.timeString(loadTime: loadTime, totalTime: totalTime)
        self.time = timeString
        showToolAction()
    }
    
    @objc func sliderTouchUpInside(_ sender: UISlider) {
        self.player?.setupSeek(progress: Double(sender.value))
        self.isDragging = false
        showToolAction()
    }
    
    @objc func sliderTouchDown(_ sender: UISlider) {
        self.isDragging = true
        showToolAction()
    }
}

extension CJPControlView {
    
    func setupToolTimer() {
        self.toolTimer?.invalidate()
        self.toolTimer = nil
        self.toolTimer = Timer.scheduledTimer(timeInterval: 4.5, target: self, selector: #selector(toolTimerAction), userInfo: nil, repeats: false)
    }
    
    @objc func toolTimerAction() {
        if isShowTool {
            hideTool()
            isShowTool = false
        } else {
            showTool()
            isShowTool = true
        }
    }
    
    func hideTool () {
        if !isShowTool {
            return
        }
        UIView.animate(withDuration: 0.3) {
            self.topView.frame = CGRect(x: 0.0, y: -self.topView.cj_height, width: self.topView.cj_width, height: self.topView.cj_height)
            self.bottomView.frame = CGRect(x: 0.0, y: self.bottomView.cj_bottom, width: self.bottomView.cj_width, height: self.bottomView.cj_height)
        } completion: { comp in
            
        }
    }
    
    func showTool() {
        if isShowTool {
            return
        }
        UIView.animate(withDuration: 0.3) {
            self.topView.frame = CGRect(x: 0.0, y: 0.0, width: self.topView.cj_width, height: self.topView.cj_height)
            
            self.bottomView.frame = CGRect(x: 0.0, y: 0.0, width: self.bottomView.cj_width, height: self.bottomView.cj_height)
            self.bottomView.cj_bottom_y = self.cj_bottom
        } completion: { comp in
            
        }
    }
    
    func singleTapAction() {
        if isShowTool {
            hideTool()
            isShowTool = false
        } else {
            showToolAction()
        }
    }
    
    func showToolAction() {
        showTool()
        isShowTool = true
        setupToolTimer()
    }
    
    func doubleTapAction() {
        actionPlay()
    }
    
    func panBegan() {
        guard let currentTime = self.player?.player?.currentItem?.currentTime().seconds,
              !currentTime.isNaN
        else { return }
        sumTime = currentTime
        showToolAction()
    }
    
    func panChanged(velocity: CGPoint) {
        if nimble.panDire == .horizontal {
            guard let totalTime = self.player?.player?.currentItem?.duration.seconds,
                  !totalTime.isNaN
            else { return }
            if totalTime == 0 { return }
            
            sumTime += velocity.x / 200.0
            sumTime = sumTime > totalTime ? totalTime : sumTime
            sumTime = sumTime < 0 ? 0 : sumTime
            
            let loadScale = Double(sumTime/totalTime)
            self.slider.value = Float(loadScale)
            let loadTime = totalTime * loadScale
            let timeString = self.player?.timeString(loadTime: loadTime, totalTime: totalTime)
            self.time = timeString
            showToolAction()
            
        } else if nimble.panDire == .vertical {
            if nimble.panLocation == .left {
                var value = UIScreen.main.brightness
                value -= velocity.y / 10000.0
                value = min(max(0, value), 1)
                UIScreen.main.brightness = value
            } else if nimble.panLocation == .right {
                var value = self.volumeSlider?.value ?? 0
                value -= Float(velocity.y / 10000.0)
                if value == 0 {
                    value = AVAudioSession.sharedInstance().outputVolume
                }
                value = min(max(0, value), 1)
                self.volumeSlider?.value = value
            }
        }
    }
    
    func panEnded() {
        guard let totalTime = self.player?.player?.currentItem?.duration.seconds,
              !totalTime.isNaN
        else { return }
        if totalTime == 0 { return }
        self.player?.setupSeek(progress: Double(sumTime/totalTime))
        showToolAction()
    }
}
